#include <iostream>
#include "../../../include/common/json/value.h"
#include "../../../include/common/json/writer.h"
#include <utility>
#include <stdexcept>
#include <cstring>
#include <cassert>
#ifdef JSON_USE_CPPTL
#include <cpptl/conststring.h>
#endif
#include <cstddef> // size_t
#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
#include "json_batchallocator.h"
#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR

#define JSON_ASSERT_UNREACHABLE assert(false)
#define JSON_ASSERT(condition) assert(condition); // @todo <= change this into an exception throw
#define JSON_ASSERT_MESSAGE(condition, message) \
  if (!(condition))                             \
    throw std::runtime_error(message);

namespace Json
{

const Value Value::null;
const Int Value::minInt = Int(~(UInt(-1) / 2));
const Int Value::maxInt = Int(UInt(-1) / 2);
const UInt Value::maxUInt = UInt(-1);

// A "safe" implementation of strdup. Allow null pointer to be passed.
// Also avoid warning on msvc80.
//
//inline char *safeStringDup( const char *czstring )
//{
//   if ( czstring )
//   {
//      const size_t length = (unsigned int)( strlen(czstring) + 1 );
//      char *newString = static_cast<char *>( malloc( length ) );
//      memcpy( newString, czstring, length );
//      return newString;
//   }
//   return 0;
//}
//
//inline char *safeStringDup( const std::string &str )
//{
//   if ( !str.empty() )
//   {
//      const size_t length = str.length();
//      char *newString = static_cast<char *>( malloc( length + 1 ) );
//      memcpy( newString, str.c_str(), length );
//      newString[length] = 0;
//      return newString;
//   }
//   return 0;
//}

ValueAllocator::~ValueAllocator()
{
}

class DefaultValueAllocator : public ValueAllocator
{
public:
  virtual ~DefaultValueAllocator()
  {
  }

  virtual char *makeMemberName(const char *memberName)
  {
    return duplicateStringValue(memberName);
  }

  virtual void releaseMemberName(char *memberName)
  {
    releaseStringValue(memberName);
  }

  virtual char *duplicateStringValue(const char *value,
                                     unsigned int length = unknown)
  {
    //@todo invesgate this old optimization
    //if ( !value  ||  value[0] == 0 )
    //   return 0;

    if (length == unknown)
      length = (unsigned int)strlen(value);
    char *newString = static_cast<char *>(malloc(length + 1));
    memcpy(newString, value, length);
    newString[length] = 0;
    return newString;
  }

  virtual void releaseStringValue(char *value)
  {
    if (value)
      free(value);
  }
};

static ValueAllocator *&valueAllocator()
{
  static DefaultValueAllocator defaultAllocator;
  static ValueAllocator *valueAllocator = &defaultAllocator;
  return valueAllocator;
}

static struct DummyValueAllocatorInitializer
{
  DummyValueAllocatorInitializer()
  {
    valueAllocator(); // ensure valueAllocator() statics are initialized before main().
  }
} dummyValueAllocatorInitializer;

// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// ValueInternals...
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
#ifdef JSON_VALUE_USE_INTERNAL_MAP
#include "json_internalarray.inl"
#include "json_internalmap.inl"
#endif // JSON_VALUE_USE_INTERNAL_MAP

#include "json_valueiterator.inl"

// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class Value::CommentInfo
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////

Value::CommentInfo::CommentInfo()
    : comment_(0)
{
}

Value::CommentInfo::~CommentInfo()
{
  if (comment_)
    valueAllocator()->releaseStringValue(comment_);
}

void Value::CommentInfo::setComment(const char *text)
{
  if (comment_)
    valueAllocator()->releaseStringValue(comment_);
  JSON_ASSERT(text);
  JSON_ASSERT_MESSAGE(text[0] == '\0' || text[0] == '/', "Comments must start with /");
  // It seems that /**/ style comments are acceptable as well.
  comment_ = valueAllocator()->duplicateStringValue(text);
}

// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class Value::CZString
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
#ifndef JSON_VALUE_USE_INTERNAL_MAP

// Notes: index_ indicates if the string was allocated when
// a string is stored.

Value::CZString::CZString(int index)
    : cstr_(0), index_(index)
{
}

Value::CZString::CZString(const char *cstr, DuplicationPolicy allocate)
    : cstr_(allocate == duplicate ? valueAllocator()->makeMemberName(cstr)
                                  : cstr),
      index_(allocate)
{
}

Value::CZString::CZString(const CZString &other)
    : cstr_(other.index_ != noDuplication && other.cstr_ != 0
                ? valueAllocator()->makeMemberName(other.cstr_)
                : other.cstr_),
      index_(other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate)
                         : other.index_)
{
}

Value::CZString::~CZString()
{
  if (cstr_ && index_ == duplicate)
    valueAllocator()->releaseMemberName(const_cast<char *>(cstr_));
}

void Value::CZString::swap(CZString &other)
{
  std::swap(cstr_, other.cstr_);
  std::swap(index_, other.index_);
}

Value::CZString &
Value::CZString::operator=(const CZString &other)
{
  CZString temp(other);
  swap(temp);
  return *this;
}

bool Value::CZString::operator<(const CZString &other) const
{
  if (cstr_)
    return strcmp(cstr_, other.cstr_) < 0;
  return index_ < other.index_;
}

bool Value::CZString::operator==(const CZString &other) const
{
  if (cstr_)
    return strcmp(cstr_, other.cstr_) == 0;
  return index_ == other.index_;
}

int Value::CZString::index() const
{
  return index_;
}

const char *
Value::CZString::c_str() const
{
  return cstr_;
}

bool Value::CZString::isStaticString() const
{
  return index_ == noDuplication;
}

#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP

// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class Value::Value
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////

/*! \internal Default constructor initialization must be equivalent to:
 * memset( this, 0, sizeof(Value) )
 * This optimization is used in ValueInternalMap fast allocator.
 */
Value::Value(ValueType type)
    : type_(type), allocated_(0), comments_(0)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
      ,
      itemIsUsed_(0)
#endif
{
  switch (type)
  {
  case nullValue:
    break;
  case intValue:
  case uintValue:
    value_.int_ = 0;
    break;
  case realValue:
    value_.real_ = 0.0;
    break;
  case stringValue:
    value_.string_ = 0;
    break;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  case arrayValue:
  case objectValue:
    value_.map_ = new ObjectValues();
    break;
#else
  case arrayValue:
    value_.array_ = arrayAllocator()->newArray();
    break;
  case objectValue:
    value_.map_ = mapAllocator()->newMap();
    break;
#endif
  case booleanValue:
    value_.bool_ = false;
    break;
  default:
    JSON_ASSERT_UNREACHABLE;
  }
}

Value::Value(Int value)
    : type_(intValue), comments_(0)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
      ,
      itemIsUsed_(0)
#endif
{
  value_.int_ = value;
}

Value::Value(UInt value)
    : type_(uintValue), comments_(0)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
      ,
      itemIsUsed_(0)
#endif
{
  value_.uint_ = value;
}

Value::Value(double value)
    : type_(realValue), comments_(0)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
      ,
      itemIsUsed_(0)
#endif
{
  value_.real_ = value;
}

Value::Value(const char *value)
    : type_(stringValue), allocated_(true), comments_(0)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
      ,
      itemIsUsed_(0)
#endif
{
  value_.string_ = valueAllocator()->duplicateStringValue(value);
}

Value::Value(const char *beginValue,
             const char *endValue)
    : type_(stringValue), allocated_(true), comments_(0)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
      ,
      itemIsUsed_(0)
#endif
{
  value_.string_ = valueAllocator()->duplicateStringValue(beginValue,
                                                          UInt(endValue - beginValue));
}

Value::Value(const std::string &value)
    : type_(stringValue), allocated_(true), comments_(0)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
      ,
      itemIsUsed_(0)
#endif
{
  value_.string_ = valueAllocator()->duplicateStringValue(value.c_str(),
                                                          (unsigned int)value.length());
}

Value::Value(const StaticString &value)
    : type_(stringValue), allocated_(false), comments_(0)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
      ,
      itemIsUsed_(0)
#endif
{
  value_.string_ = const_cast<char *>(value.c_str());
}

#ifdef JSON_USE_CPPTL
Value::Value(const CppTL::ConstString &value)
    : type_(stringValue), allocated_(true), comments_(0)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
      ,
      itemIsUsed_(0)
#endif
{
  value_.string_ = valueAllocator()->duplicateStringValue(value, value.length());
}
#endif

Value::Value(bool value)
    : type_(booleanValue), comments_(0)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
      ,
      itemIsUsed_(0)
#endif
{
  value_.bool_ = value;
}

Value::Value(const Value &other)
    : type_(other.type_), comments_(0)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
      ,
      itemIsUsed_(0)
#endif
{
  switch (type_)
  {
  case nullValue:
  case intValue:
  case uintValue:
  case realValue:
  case booleanValue:
    value_ = other.value_;
    break;
  case stringValue:
    if (other.value_.string_)
    {
      value_.string_ = valueAllocator()->duplicateStringValue(other.value_.string_);
      allocated_ = true;
    }
    else
      value_.string_ = 0;
    break;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  case arrayValue:
  case objectValue:
    value_.map_ = new ObjectValues(*other.value_.map_);
    break;
#else
  case arrayValue:
    value_.array_ = arrayAllocator()->newArrayCopy(*other.value_.array_);
    break;
  case objectValue:
    value_.map_ = mapAllocator()->newMapCopy(*other.value_.map_);
    break;
#endif
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  if (other.comments_)
  {
    comments_ = new CommentInfo[numberOfCommentPlacement];
    for (int comment = 0; comment < numberOfCommentPlacement; ++comment)
    {
      const CommentInfo &otherComment = other.comments_[comment];
      if (otherComment.comment_)
        comments_[comment].setComment(otherComment.comment_);
    }
  }
}

Value::~Value()
{
  switch (type_)
  {
  case nullValue:
  case intValue:
  case uintValue:
  case realValue:
  case booleanValue:
    break;
  case stringValue:
    if (allocated_)
      valueAllocator()->releaseStringValue(value_.string_);
    break;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  case arrayValue:
  case objectValue:
    delete value_.map_;
    break;
#else
  case arrayValue:
    arrayAllocator()->destructArray(value_.array_);
    break;
  case objectValue:
    mapAllocator()->destructMap(value_.map_);
    break;
#endif
  default:
    JSON_ASSERT_UNREACHABLE;
  }

  if (comments_)
    delete[] comments_;
}

Value &
Value::operator=(const Value &other)
{
  Value temp(other);
  swap(temp);
  return *this;
}

void Value::swap(Value &other)
{
  ValueType temp = type_;
  type_ = other.type_;
  other.type_ = temp;
  std::swap(value_, other.value_);
  int temp2 = allocated_;
  allocated_ = other.allocated_;
  other.allocated_ = temp2;
}

ValueType
Value::type() const
{
  return type_;
}

int Value::compare(const Value &other)
{
  /*
   int typeDelta = other.type_ - type_;
   switch ( type_ )
   {
   case nullValue:

      return other.type_ == type_;
   case intValue:
      if ( other.type_.isNumeric()
   case uintValue:
   case realValue:
   case booleanValue:
      break;
   case stringValue,
      break;
   case arrayValue:
      delete value_.array_;
      break;
   case objectValue:
      delete value_.map_;
   default:
      JSON_ASSERT_UNREACHABLE;
   }
   */
  return 0; // unreachable
}

bool Value::operator<(const Value &other) const
{
  int typeDelta = type_ - other.type_;
  if (typeDelta)
    return typeDelta < 0 ? true : false;
  switch (type_)
  {
  case nullValue:
    return false;
  case intValue:
    return value_.int_ < other.value_.int_;
  case uintValue:
    return value_.uint_ < other.value_.uint_;
  case realValue:
    return value_.real_ < other.value_.real_;
  case booleanValue:
    return value_.bool_ < other.value_.bool_;
  case stringValue:
    return (value_.string_ == 0 && other.value_.string_) || (other.value_.string_ && value_.string_ && strcmp(value_.string_, other.value_.string_) < 0);
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  case arrayValue:
  case objectValue:
  {
    int delta = int(value_.map_->size() - other.value_.map_->size());
    if (delta)
      return delta < 0;
    return (*value_.map_) < (*other.value_.map_);
  }
#else
  case arrayValue:
    return value_.array_->compare(*(other.value_.array_)) < 0;
  case objectValue:
    return value_.map_->compare(*(other.value_.map_)) < 0;
#endif
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  return 0; // unreachable
}

bool Value::operator<=(const Value &other) const
{
  return !(other > *this);
}

bool Value::operator>=(const Value &other) const
{
  return !(*this < other);
}

bool Value::operator>(const Value &other) const
{
  return other < *this;
}

bool Value::operator==(const Value &other) const
{
  //if ( type_ != other.type_ )
  // GCC 2.95.3 says:
  // attempt to take address of bit-field structure member `Json::Value::type_'
  // Beats me, but a temp solves the problem.
  int temp = other.type_;
  if (type_ != temp)
    return false;
  switch (type_)
  {
  case nullValue:
    return true;
  case intValue:
    return value_.int_ == other.value_.int_;
  case uintValue:
    return value_.uint_ == other.value_.uint_;
  case realValue:
    return value_.real_ == other.value_.real_;
  case booleanValue:
    return value_.bool_ == other.value_.bool_;
  case stringValue:
    return (value_.string_ == other.value_.string_) || (other.value_.string_ && value_.string_ && strcmp(value_.string_, other.value_.string_) == 0);
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  case arrayValue:
  case objectValue:
    return value_.map_->size() == other.value_.map_->size() && (*value_.map_) == (*other.value_.map_);
#else
  case arrayValue:
    return value_.array_->compare(*(other.value_.array_)) == 0;
  case objectValue:
    return value_.map_->compare(*(other.value_.map_)) == 0;
#endif
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  return 0; // unreachable
}

bool Value::operator!=(const Value &other) const
{
  return !(*this == other);
}

const char *
Value::asCString() const
{
  JSON_ASSERT(type_ == stringValue);
  return value_.string_;
}

std::string
Value::asString() const
{
  switch (type_)
  {
  case nullValue:
    return "";
  case stringValue:
    return value_.string_ ? value_.string_ : "";
  case booleanValue:
    return value_.bool_ ? "true" : "false";
  case intValue:
  case uintValue:
  case realValue:
  case arrayValue:
  case objectValue:
    JSON_ASSERT_MESSAGE(false, "Type is not convertible to string");
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  return ""; // unreachable
}

#ifdef JSON_USE_CPPTL
CppTL::ConstString
Value::asConstString() const
{
  return CppTL::ConstString(asString().c_str());
}
#endif

Value::Int
Value::asInt() const
{
  switch (type_)
  {
  case nullValue:
    return 0;
  case intValue:
    return value_.int_;
  case uintValue:
    JSON_ASSERT_MESSAGE(value_.uint_ < (unsigned)maxInt, "integer out of signed integer range");
    return value_.uint_;
  case realValue:
    JSON_ASSERT_MESSAGE(value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range");
    return Int(value_.real_);
  case booleanValue:
    return value_.bool_ ? 1 : 0;
  case stringValue:
  case arrayValue:
  case objectValue:
    JSON_ASSERT_MESSAGE(false, "Type is not convertible to int");
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  return 0; // unreachable;
}

Value::UInt
Value::asUInt() const
{
  switch (type_)
  {
  case nullValue:
    return 0;
  case intValue:
    JSON_ASSERT_MESSAGE(value_.int_ >= 0, "Negative integer can not be converted to unsigned integer");
    return value_.int_;
  case uintValue:
    return value_.uint_;
  case realValue:
    JSON_ASSERT_MESSAGE(value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range");
    return UInt(value_.real_);
  case booleanValue:
    return value_.bool_ ? 1 : 0;
  case stringValue:
  case arrayValue:
  case objectValue:
    JSON_ASSERT_MESSAGE(false, "Type is not convertible to uint");
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  return 0; // unreachable;
}

double
Value::asDouble() const
{
  switch (type_)
  {
  case nullValue:
    return 0.0;
  case intValue:
    return value_.int_;
  case uintValue:
    return value_.uint_;
  case realValue:
    return value_.real_;
  case booleanValue:
    return value_.bool_ ? 1.0 : 0.0;
  case stringValue:
  case arrayValue:
  case objectValue:
    JSON_ASSERT_MESSAGE(false, "Type is not convertible to double");
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  return 0; // unreachable;
}

bool Value::asBool() const
{
  switch (type_)
  {
  case nullValue:
    return false;
  case intValue:
  case uintValue:
    return value_.int_ != 0;
  case realValue:
    return value_.real_ != 0.0;
  case booleanValue:
    return value_.bool_;
  case stringValue:
    return value_.string_ && value_.string_[0] != 0;
  case arrayValue:
  case objectValue:
    return value_.map_->size() != 0;
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  return false; // unreachable;
}

bool Value::isConvertibleTo(ValueType other) const
{
  switch (type_)
  {
  case nullValue:
    return true;
  case intValue:
    return (other == nullValue && value_.int_ == 0) || other == intValue || (other == uintValue && value_.int_ >= 0) || other == realValue || other == stringValue || other == booleanValue;
  case uintValue:
    return (other == nullValue && value_.uint_ == 0) || (other == intValue && value_.uint_ <= (unsigned)maxInt) || other == uintValue || other == realValue || other == stringValue || other == booleanValue;
  case realValue:
    return (other == nullValue && value_.real_ == 0.0) || (other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt) || (other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt) || other == realValue || other == stringValue || other == booleanValue;
  case booleanValue:
    return (other == nullValue && value_.bool_ == false) || other == intValue || other == uintValue || other == realValue || other == stringValue || other == booleanValue;
  case stringValue:
    return other == stringValue || (other == nullValue && (!value_.string_ || value_.string_[0] == 0));
  case arrayValue:
    return other == arrayValue || (other == nullValue && value_.map_->size() == 0);
  case objectValue:
    return other == objectValue || (other == nullValue && value_.map_->size() == 0);
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  return false; // unreachable;
}

/// Number of values in array or object
Value::UInt
Value::size() const
{
  switch (type_)
  {
  case nullValue:
  case intValue:
  case uintValue:
  case realValue:
  case booleanValue:
  case stringValue:
    return 0;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  case arrayValue: // size of the array is highest index + 1
    if (!value_.map_->empty())
    {
      ObjectValues::const_iterator itLast = value_.map_->end();
      --itLast;
      return (*itLast).first.index() + 1;
    }
    return 0;
  case objectValue:
    return Int(value_.map_->size());
#else
  case arrayValue:
    return Int(value_.array_->size());
  case objectValue:
    return Int(value_.map_->size());
#endif
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  return 0; // unreachable;
}

bool Value::empty() const
{
  if (isNull() || isArray() || isObject())
    return size() == 0u;
  else
    return false;
}

bool Value::operator!() const
{
  return isNull();
}

void Value::clear()
{
  JSON_ASSERT(type_ == nullValue || type_ == arrayValue || type_ == objectValue);

  switch (type_)
  {
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  case arrayValue:
  case objectValue:
    value_.map_->clear();
    break;
#else
  case arrayValue:
    value_.array_->clear();
    break;
  case objectValue:
    value_.map_->clear();
    break;
#endif
  default:
    break;
  }
}

void Value::resize(UInt newSize)
{
  JSON_ASSERT(type_ == nullValue || type_ == arrayValue);
  if (type_ == nullValue)
    *this = Value(arrayValue);
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  UInt oldSize = size();
  if (newSize == 0)
    clear();
  else if (newSize > oldSize)
    (*this)[newSize - 1];
  else
  {
    for (UInt index = newSize; index < oldSize; ++index)
      value_.map_->erase(index);
    assert(size() == newSize);
  }
#else
  value_.array_->resize(newSize);
#endif
}

Value &
    Value::operator[](UInt index)
{
  JSON_ASSERT(type_ == nullValue || type_ == arrayValue);
  if (type_ == nullValue)
    *this = Value(arrayValue);
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  CZString key(index);
  ObjectValues::iterator it = value_.map_->lower_bound(key);
  if (it != value_.map_->end() && (*it).first == key)
    return (*it).second;

  ObjectValues::value_type defaultValue(key, null);
  it = value_.map_->insert(it, defaultValue);
  return (*it).second;
#else
  return value_.array_->resolveReference(index);
#endif
}

const Value &
    Value::operator[](UInt index) const
{
  JSON_ASSERT(type_ == nullValue || type_ == arrayValue);
  if (type_ == nullValue)
    return null;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  CZString key(index);
  ObjectValues::const_iterator it = value_.map_->find(key);
  if (it == value_.map_->end())
    return null;
  return (*it).second;
#else
  Value *value = value_.array_->find(index);
  return value ? *value : null;
#endif
}

Value &
    Value::operator[](const char *key)
{
  return resolveReference(key, false);
}

Value &
Value::resolveReference(const char *key,
                        bool isStatic)
{
  JSON_ASSERT(type_ == nullValue || type_ == objectValue);
  if (type_ == nullValue)
    *this = Value(objectValue);
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  CZString actualKey(key, isStatic ? CZString::noDuplication
                                   : CZString::duplicateOnCopy);
  ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
  if (it != value_.map_->end() && (*it).first == actualKey)
    return (*it).second;

  ObjectValues::value_type defaultValue(actualKey, null);
  it = value_.map_->insert(it, defaultValue);
  Value &value = (*it).second;
  return value;
#else
  return value_.map_->resolveReference(key, isStatic);
#endif
}

Value Value::get(UInt index,
                 const Value &defaultValue) const
{
  const Value *value = &((*this)[index]);
  return value == &null ? defaultValue : *value;
}

bool Value::isValidIndex(UInt index) const
{
  return index < size();
}

const Value &
    Value::operator[](const char *key) const
{
  JSON_ASSERT(type_ == nullValue || type_ == objectValue);
  if (type_ == nullValue)
    return null;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  CZString actualKey(key, CZString::noDuplication);
  ObjectValues::const_iterator it = value_.map_->find(actualKey);
  if (it == value_.map_->end())
    return null;
  return (*it).second;
#else
  const Value *value = value_.map_->find(key);
  return value ? *value : null;
#endif
}

Value &
    Value::operator[](const std::string &key)
{
  return (*this)[key.c_str()];
}

const Value &
    Value::operator[](const std::string &key) const
{
  return (*this)[key.c_str()];
}

Value &
    Value::operator[](const StaticString &key)
{
  return resolveReference(key, true);
}

#ifdef JSON_USE_CPPTL
Value &
    Value::operator[](const CppTL::ConstString &key)
{
  return (*this)[key.c_str()];
}

const Value &
    Value::operator[](const CppTL::ConstString &key) const
{
  return (*this)[key.c_str()];
}
#endif

Value &
Value::append(const Value &value)
{
  return (*this)[size()] = value;
}

Value Value::get(const char *key,
                 const Value &defaultValue) const
{
  const Value *value = &((*this)[key]);
  return value == &null ? defaultValue : *value;
}

Value Value::get(const std::string &key,
                 const Value &defaultValue) const
{
  return get(key.c_str(), defaultValue);
}

Value Value::removeMember(const char *key)
{
  JSON_ASSERT(type_ == nullValue || type_ == objectValue);
  if (type_ == nullValue)
    return null;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  CZString actualKey(key, CZString::noDuplication);
  ObjectValues::iterator it = value_.map_->find(actualKey);
  if (it == value_.map_->end())
    return null;
  Value old(it->second);
  value_.map_->erase(it);
  return old;
#else
  Value *value = value_.map_->find(key);
  if (value)
  {
    Value old(*value);
    value_.map_.remove(key);
    return old;
  }
  else
  {
    return null;
  }
#endif
}

Value Value::removeMember(const std::string &key)
{
  return removeMember(key.c_str());
}

#ifdef JSON_USE_CPPTL
Value Value::get(const CppTL::ConstString &key,
                 const Value &defaultValue) const
{
  return get(key.c_str(), defaultValue);
}
#endif

bool Value::isMember(const char *key) const
{
  const Value *value = &((*this)[key]);
  return value != &null;
}

bool Value::isMember(const std::string &key) const
{
  return isMember(key.c_str());
}

#ifdef JSON_USE_CPPTL
bool Value::isMember(const CppTL::ConstString &key) const
{
  return isMember(key.c_str());
}
#endif

Value::Members
Value::getMemberNames() const
{
  JSON_ASSERT(type_ == nullValue || type_ == objectValue);
  if (type_ == nullValue)
    return Value::Members();
  Members members;
  members.reserve(value_.map_->size());
#ifndef JSON_VALUE_USE_INTERNAL_MAP
  ObjectValues::const_iterator it = value_.map_->begin();
  ObjectValues::const_iterator itEnd = value_.map_->end();
  for (; it != itEnd; ++it)
    members.push_back(std::string((*it).first.c_str()));
#else
  ValueInternalMap::IteratorState it;
  ValueInternalMap::IteratorState itEnd;
  value_.map_->makeBeginIterator(it);
  value_.map_->makeEndIterator(itEnd);
  for (; !ValueInternalMap::equals(it, itEnd); ValueInternalMap::increment(it))
    members.push_back(std::string(ValueInternalMap::key(it)));
#endif
  return members;
}
//
//# ifdef JSON_USE_CPPTL
//EnumMemberNames
//Value::enumMemberNames() const
//{
//   if ( type_ == objectValue )
//   {
//      return CppTL::Enum::any(  CppTL::Enum::transform(
//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
//         MemberNamesTransform() ) );
//   }
//   return EnumMemberNames();
//}
//
//
//EnumValues
//Value::enumValues() const
//{
//   if ( type_ == objectValue  ||  type_ == arrayValue )
//      return CppTL::Enum::anyValues( *(value_.map_),
//                                     CppTL::Type<const Value &>() );
//   return EnumValues();
//}
//
//# endif

bool Value::isNull() const
{
  return type_ == nullValue;
}

bool Value::isBool() const
{
  return type_ == booleanValue;
}

bool Value::isInt() const
{
  return type_ == intValue;
}

bool Value::isUInt() const
{
  return type_ == uintValue;
}

bool Value::isIntegral() const
{
  return type_ == intValue || type_ == uintValue || type_ == booleanValue;
}

bool Value::isDouble() const
{
  return type_ == realValue;
}

bool Value::isNumeric() const
{
  return isIntegral() || isDouble();
}

bool Value::isString() const
{
  return type_ == stringValue;
}

bool Value::isArray() const
{
  return type_ == nullValue || type_ == arrayValue;
}

bool Value::isObject() const
{
  return type_ == nullValue || type_ == objectValue;
}

void Value::setComment(const char *comment,
                       CommentPlacement placement)
{
  if (!comments_)
    comments_ = new CommentInfo[numberOfCommentPlacement];
  comments_[placement].setComment(comment);
}

void Value::setComment(const std::string &comment,
                       CommentPlacement placement)
{
  setComment(comment.c_str(), placement);
}

bool Value::hasComment(CommentPlacement placement) const
{
  return comments_ != 0 && comments_[placement].comment_ != 0;
}

std::string
Value::getComment(CommentPlacement placement) const
{
  if (hasComment(placement))
    return comments_[placement].comment_;
  return "";
}

std::string
Value::toStyledString() const
{
  StyledWriter writer;
  return writer.write(*this);
}

Value::const_iterator
Value::begin() const
{
  switch (type_)
  {
#ifdef JSON_VALUE_USE_INTERNAL_MAP
  case arrayValue:
    if (value_.array_)
    {
      ValueInternalArray::IteratorState it;
      value_.array_->makeBeginIterator(it);
      return const_iterator(it);
    }
    break;
  case objectValue:
    if (value_.map_)
    {
      ValueInternalMap::IteratorState it;
      value_.map_->makeBeginIterator(it);
      return const_iterator(it);
    }
    break;
#else
  case arrayValue:
  case objectValue:
    if (value_.map_)
      return const_iterator(value_.map_->begin());
    break;
#endif
  default:
    break;
  }
  return const_iterator();
}

Value::const_iterator
Value::end() const
{
  switch (type_)
  {
#ifdef JSON_VALUE_USE_INTERNAL_MAP
  case arrayValue:
    if (value_.array_)
    {
      ValueInternalArray::IteratorState it;
      value_.array_->makeEndIterator(it);
      return const_iterator(it);
    }
    break;
  case objectValue:
    if (value_.map_)
    {
      ValueInternalMap::IteratorState it;
      value_.map_->makeEndIterator(it);
      return const_iterator(it);
    }
    break;
#else
  case arrayValue:
  case objectValue:
    if (value_.map_)
      return const_iterator(value_.map_->end());
    break;
#endif
  default:
    break;
  }
  return const_iterator();
}

Value::iterator
Value::begin()
{
  switch (type_)
  {
#ifdef JSON_VALUE_USE_INTERNAL_MAP
  case arrayValue:
    if (value_.array_)
    {
      ValueInternalArray::IteratorState it;
      value_.array_->makeBeginIterator(it);
      return iterator(it);
    }
    break;
  case objectValue:
    if (value_.map_)
    {
      ValueInternalMap::IteratorState it;
      value_.map_->makeBeginIterator(it);
      return iterator(it);
    }
    break;
#else
  case arrayValue:
  case objectValue:
    if (value_.map_)
      return iterator(value_.map_->begin());
    break;
#endif
  default:
    break;
  }
  return iterator();
}

Value::iterator
Value::end()
{
  switch (type_)
  {
#ifdef JSON_VALUE_USE_INTERNAL_MAP
  case arrayValue:
    if (value_.array_)
    {
      ValueInternalArray::IteratorState it;
      value_.array_->makeEndIterator(it);
      return iterator(it);
    }
    break;
  case objectValue:
    if (value_.map_)
    {
      ValueInternalMap::IteratorState it;
      value_.map_->makeEndIterator(it);
      return iterator(it);
    }
    break;
#else
  case arrayValue:
  case objectValue:
    if (value_.map_)
      return iterator(value_.map_->end());
    break;
#endif
  default:
    break;
  }
  return iterator();
}

// class PathArgument
// //////////////////////////////////////////////////////////////////

PathArgument::PathArgument()
    : kind_(kindNone)
{
}

PathArgument::PathArgument(Value::UInt index)
    : index_(index), kind_(kindIndex)
{
}

PathArgument::PathArgument(const char *key)
    : key_(key), kind_(kindKey)
{
}

PathArgument::PathArgument(const std::string &key)
    : key_(key.c_str()), kind_(kindKey)
{
}

// class Path
// //////////////////////////////////////////////////////////////////

Path::Path(const std::string &path,
           const PathArgument &a1,
           const PathArgument &a2,
           const PathArgument &a3,
           const PathArgument &a4,
           const PathArgument &a5)
{
  InArgs in;
  in.push_back(&a1);
  in.push_back(&a2);
  in.push_back(&a3);
  in.push_back(&a4);
  in.push_back(&a5);
  makePath(path, in);
}

void Path::makePath(const std::string &path,
                    const InArgs &in)
{
  const char *current = path.c_str();
  const char *end = current + path.length();
  InArgs::const_iterator itInArg = in.begin();
  while (current != end)
  {
    if (*current == '[')
    {
      ++current;
      if (*current == '%')
        addPathInArg(path, in, itInArg, PathArgument::kindIndex);
      else
      {
        Value::UInt index = 0;
        for (; current != end && *current >= '0' && *current <= '9'; ++current)
          index = index * 10 + Value::UInt(*current - '0');
        args_.push_back(index);
      }
      if (current == end || *current++ != ']')
        invalidPath(path, int(current - path.c_str()));
    }
    else if (*current == '%')
    {
      addPathInArg(path, in, itInArg, PathArgument::kindKey);
      ++current;
    }
    else if (*current == '.')
    {
      ++current;
    }
    else
    {
      const char *beginName = current;
      while (current != end && !strchr("[.", *current))
        ++current;
      args_.push_back(std::string(beginName, current));
    }
  }
}

void Path::addPathInArg(const std::string &path,
                        const InArgs &in,
                        InArgs::const_iterator &itInArg,
                        PathArgument::Kind kind)
{
  if (itInArg == in.end())
  {
    // Error: missing argument %d
  }
  else if ((*itInArg)->kind_ != kind)
  {
    // Error: bad argument type
  }
  else
  {
    args_.push_back(**itInArg);
  }
}

void Path::invalidPath(const std::string &path,
                       int location)
{
  // Error: invalid path.
}

const Value &
Path::resolve(const Value &root) const
{
  const Value *node = &root;
  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it)
  {
    const PathArgument &arg = *it;
    if (arg.kind_ == PathArgument::kindIndex)
    {
      if (!node->isArray() || node->isValidIndex(arg.index_))
      {
        // Error: unable to resolve path (array value expected at position...
      }
      node = &((*node)[arg.index_]);
    }
    else if (arg.kind_ == PathArgument::kindKey)
    {
      if (!node->isObject())
      {
        // Error: unable to resolve path (object value expected at position...)
      }
      node = &((*node)[arg.key_]);
      if (node == &Value::null)
      {
        // Error: unable to resolve path (object has no member named '' at position...)
      }
    }
  }
  return *node;
}

Value Path::resolve(const Value &root,
                    const Value &defaultValue) const
{
  const Value *node = &root;
  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it)
  {
    const PathArgument &arg = *it;
    if (arg.kind_ == PathArgument::kindIndex)
    {
      if (!node->isArray() || node->isValidIndex(arg.index_))
        return defaultValue;
      node = &((*node)[arg.index_]);
    }
    else if (arg.kind_ == PathArgument::kindKey)
    {
      if (!node->isObject())
        return defaultValue;
      node = &((*node)[arg.key_]);
      if (node == &Value::null)
        return defaultValue;
    }
  }
  return *node;
}

Value &
Path::make(Value &root) const
{
  Value *node = &root;
  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it)
  {
    const PathArgument &arg = *it;
    if (arg.kind_ == PathArgument::kindIndex)
    {
      if (!node->isArray())
      {
        // Error: node is not an array at position ...
      }
      node = &((*node)[arg.index_]);
    }
    else if (arg.kind_ == PathArgument::kindKey)
    {
      if (!node->isObject())
      {
        // Error: node is not an object at position...
      }
      node = &((*node)[arg.key_]);
    }
  }
  return *node;
}

} // namespace Json
